/*
 * Copyright (C) 2001-2011 Jacek Sieka, arnetheduck on gmail point com
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

#if !defined(PRIVATE_FRAME_H)
#define PRIVATE_FRAME_H

//[-]PPA [Doxygen 1.5.1] #include "../client/User.h"
#include "../client/ClientManagerListener.h"
#include "../client/ResourceManager.h"

#include "FlatTabCtrl.h"
//[-]PPA [Doxygen 1.5.1] #include "WinUtil.h"
//[-]PPA [Doxygen 1.5.1] #include "UCHandler.h"
#include "HubFrame.h"
#include "../client/QueueManager.h"

#include "ChatCtrl.h"
#include "ResourceLoader.h" // [+] InfinitySky. PNG Support from Apex 1.3.8.
#include "MessagePanel.h"

#define PM_MESSAGE_MAP 8        // This could be any number, really...

class PrivateFrame : public MDITabChildWindowImpl < PrivateFrame, RGB(0, 255, 255), IDR_PRIVATE, IDR_PRIVATE_OFF > ,
	private ClientManagerListener, public UCHandler<PrivateFrame>, private SettingsManagerListener
{
	public:
		static void gotMessage(const string &strFromUserName, Identity& from, const UserPtr& to, const UserPtr& replyTo, const tstring& aMessage, Client* c, bool thirdPerson); // !SMT!-S
		static void openWindow(const HintedUser& replyTo, const tstring& aMessage = Util::emptyStringT, Client* c = NULL);
		static bool isOpen(const UserPtr& u)
		{
			return frames.find(u) != frames.end();
		}
		static bool closeUser(const UserPtr& u); // !SMT!-S
		static void closeAll();
		static void closeAllOffline();
		
		enum
		{
			USER_UPDATED
		};
		
		DECLARE_FRAME_WND_CLASS_EX(_T("PrivateFrame"), IDR_PRIVATE, 0, COLOR_3DFACE);
		
		typedef MDITabChildWindowImpl < PrivateFrame, RGB(0, 255, 255), IDR_PRIVATE, IDR_PRIVATE_OFF > baseClass;
		typedef UCHandler<PrivateFrame> ucBase;
		
		BEGIN_MSG_MAP(PrivateFrame)
		MESSAGE_HANDLER(WM_SETFOCUS, onFocus)
		MESSAGE_HANDLER(WM_CREATE, OnCreate)
		MESSAGE_HANDLER(WM_CTLCOLOREDIT, onCtlColor)
		MESSAGE_HANDLER(WM_CTLCOLORSTATIC, onCtlColor)
		MESSAGE_HANDLER(WM_CLOSE, onClose)
		MESSAGE_HANDLER(WM_SPEAKER, onSpeaker)
		MESSAGE_HANDLER(WM_CONTEXTMENU, onContextMenu)
		MESSAGE_HANDLER(FTM_CONTEXTMENU, onTabContextMenu)
		COMMAND_ID_HANDLER(IDC_GETLIST, onGetList)
		COMMAND_ID_HANDLER(IDC_MATCH_QUEUE, onMatchQueue)
		COMMAND_ID_HANDLER(IDC_GRANTSLOT, onGrantSlot)
		COMMAND_ID_HANDLER(IDC_GRANTSLOT_HOUR, onGrantSlotHour)
		COMMAND_ID_HANDLER(IDC_GRANTSLOT_DAY, onGrantSlotDay)
		COMMAND_ID_HANDLER(IDC_GRANTSLOT_WEEK, onGrantSlotWeek)
		COMMAND_ID_HANDLER(IDC_GRANTSLOT_PERIOD, onGrantSlotPeriod) // !SMT!-UI
		COMMAND_ID_HANDLER(IDC_UNGRANTSLOT, onUnGrantSlot)
		COMMAND_ID_HANDLER(IDC_ADD_TO_FAVORITES, onAddToFavorites)
		COMMAND_ID_HANDLER(IDC_SEND_MESSAGE, onSendMessage)
		COMMAND_ID_HANDLER(IDC_CLOSE_ALL_OFFLINE_PM, onCloseAllOffline) // [+] InfinitySky.
		COMMAND_ID_HANDLER(IDC_CLOSE_ALL_PM, onCloseAll) // [+] InfinitySky.
		COMMAND_ID_HANDLER(IDC_CLOSE_WINDOW, onCloseWindow)
		COMMAND_ID_HANDLER(ID_EDIT_COPY, onEditCopy)
		COMMAND_ID_HANDLER(ID_EDIT_SELECT_ALL, onEditSelectAll)
		COMMAND_ID_HANDLER(ID_EDIT_CLEAR_ALL, onEditClearAll)
		COMMAND_ID_HANDLER(IDC_COPY_ACTUAL_LINE, onCopyActualLine)
		COMMAND_ID_HANDLER(IDC_OPEN_USER_LOG, onOpenUserLog)
		COMMAND_ID_HANDLER(IDC_COPY_URL, onCopyURL)
		COMMAND_ID_HANDLER(IDC_EMOT, onEmoticons)
		COMMAND_ID_HANDLER(IDC_WINAMP_SPAM, onWinampSpam)
		// Fix for the tab menu functions - begin
		COMMAND_ID_HANDLER(IDC_REPORT, onOPFunc)
//      COMMAND_ID_HANDLER(IDC_CHECKLIST, onOPFunc) // [-] IRainman old, dead code
		COMMAND_ID_HANDLER(IDC_GET_USER_RESPONSES, onOPFunc) // [-] IRainman old, dead code
		// Fix for the tab menu functions - end
		COMMAND_RANGE_HANDLER(IDC_EMOMENU, IDC_EMOMENU + msgPanel.GetEmotionMenuItemsCount(), onEmoPackChange)
		COMMAND_RANGE_HANDLER(IDC_BOLD, IDC_STRIKE, onTextStyleSelect)
		COMMAND_ID_HANDLER(ID_TEXT_TRANSCODE, OnTextTranscode)
		CHAIN_COMMANDS(ucBase)
		CHAIN_MSG_MAP(baseClass)
		NOTIFY_HANDLER(IDC_CLIENT, EN_LINK, onClientEnLink)
		ALT_MSG_MAP(PM_MESSAGE_MAP)
		MESSAGE_HANDLER(WM_CHAR, onChar)
		MESSAGE_HANDLER(WM_KEYDOWN, onChar)
		MESSAGE_HANDLER(WM_KEYUP, onChar)
		MESSAGE_HANDLER(WM_LBUTTONDBLCLK, onLButton) // !Decker!
		END_MSG_MAP()
		
		LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled);
		LRESULT onChar(UINT uMsg, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled);
		LRESULT onGetList(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/);
		LRESULT onMatchQueue(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/);
		LRESULT onGrantSlot(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/);
		LRESULT onGrantSlotHour(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/);
		LRESULT onGrantSlotDay(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/);
		LRESULT onGrantSlotWeek(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/);
		LRESULT onGrantSlotPeriod(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/); // !SMT!-UI
		LRESULT onUnGrantSlot(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/);
		LRESULT onAddToFavorites(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/);
		LRESULT onTabContextMenu(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/);
		LRESULT onContextMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
		LRESULT onEditCopy(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/);
		LRESULT onEditSelectAll(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/);
		LRESULT onEditClearAll(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/);
		LRESULT onCopyActualLine(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/);
		LRESULT onClientEnLink(int idCtrl, LPNMHDR pnmh, BOOL& bHandled);
		LRESULT onOpenUserLog(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/);
		LRESULT onCopyURL(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/);
		LRESULT onEmoPackChange(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/);
		LRESULT onLButton(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled); // !Decker!
		LRESULT onTextStyleSelect(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
		{
			WinUtil::SetBBCodeForCEdit(ctrlMessage, wID);
			return 0;
		}
		
		// Fix for the tab menu functions - begin
		LRESULT onOPFunc(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
		{
			switch (wID)
			{
				case IDC_REPORT:
					ClientManager::getInstance()->reportUser(HintedUser(replyTo, getHubHint()));
					break;
					// [-] IRainman old, dead code
					//case IDC_CHECKLIST:
					//  try
					//  {
					//      QueueManager::getInstance()->addList(HintedUser(replyTo, getHubHint()), QueueItem::FLAG_CHECK_FILE_LIST);
					//  }
					//  catch (const Exception& e)
					//  {
					//      LogManager::getInstance()->message(e.getError());
					//  }
					//  break;
				case IDC_GET_USER_RESPONSES:
					try
					{
						QueueManager::getInstance()->addCheckUserIP(HintedUser(getUser(), getHubHint())); // [+] SSA
					}
					catch (const Exception& e)
					{
						LogManager::getInstance()->message(e.getError());
					}
					break;
			}
			return 0;
		}
		// Fix for the tab menu functions - end
		
		LRESULT onWinampSpam(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
		{
			tstring cmd, param, message, status;
			if (SETTING(MEDIA_PLAYER) == SettingsManager::WinAmp)
			{
				cmd = _T("/winamp");
			}
			else if (SETTING(MEDIA_PLAYER) == SettingsManager::WinMediaPlayer)
			{
				cmd = _T("/wmp");
			}
			else if (SETTING(MEDIA_PLAYER) == SettingsManager::iTunes)
			{
				cmd = _T("/itunes");
			}
			else if (SETTING(MEDIA_PLAYER) == SettingsManager::WinMediaPlayerClassic)
			{
				cmd = _T("/mpc");
			}
			else if (SETTING(MEDIA_PLAYER) == SettingsManager::JetAudio)
			{
				cmd = _T("/ja");
			}
			else
			{
				addClientLine(CTSTRING(NO_MEDIA_SPAM));
				return 0;
			}
			if (WinUtil::checkCommand(cmd, param, message, status))
			{
				if (!message.empty())
				{
					sendMessage(message);
				}
				if (!status.empty())
				{
					addClientLine(status);
				}
			}
			return 0;
		}
		
		const string& getHubHint() const
		{
			return ctrlClient.getClient() ? ctrlClient.getClient()->getHubUrl() : Util::emptyString;
		}
		
		LRESULT onEmoticons(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled)
		{
			return msgPanel.onEmoticons(wNotifyCode, wID, hWndCtl, bHandled);
		}
		
		void addLine(const tstring& aLine, CHARFORMAT2& cf);
		void addLine(const string &strFromUserName, const Identity&, const tstring& aLine);
		void addLine(const string &strFromUserName, const Identity&, const tstring& aLine, CHARFORMAT2& cf);
		void onEnter();
		void UpdateLayout(BOOL bResizeBars = TRUE);
		void runUserCommand(UserCommand& uc);
		void readLog();
		
		LRESULT onClose(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled);
		
		LRESULT onSendMessage(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
		{
			onEnter();
			return 0;
		}
		
		LRESULT onCloseWindow(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
		{
			PostMessage(WM_CLOSE);
			return 0;
		}
		
		// [+] InfinitySky.
		LRESULT onCloseAll(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
		{
			closeAll();
			return 0;
		}
		
		// [+] InfinitySky.
		LRESULT onCloseAllOffline(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
		{
			closeAllOffline();
			return 0;
		}
		
		LRESULT PrivateFrame::onSpeaker(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /* bHandled */)
		{
			updateTitle();
			return 0;
		}
		
		LRESULT onCtlColor(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
		{
			HWND hWnd = (HWND)lParam;
			HDC hDC = (HDC)wParam;
			if (hWnd == ctrlClient.m_hWnd || hWnd == ctrlMessage.m_hWnd)
			{
				::SetBkColor(hDC, WinUtil::bgColor);
				::SetTextColor(hDC, WinUtil::textColor);
				return (LRESULT)WinUtil::bgBrush;
			}
			bHandled = FALSE;
			return FALSE;
		}
		
		LRESULT onFocus(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
		{
			ctrlMessage.SetFocus();
			ctrlClient.GoToEnd();
			return 0;
		}
		
		void addClientLine(const tstring& aLine)
		{
			if (!created)
			{
				CreateEx(WinUtil::mdiClient);
			}
			ctrlStatus.SetText(0, (_T("[") + Text::toT(Util::getShortTimeString()) + _T("] ") + aLine).c_str());
			if (BOOLSETTING(BOLD_PM))
			{
				setDirty();
			}
		}
		
		void sendMessage(const tstring& msg);
		
		UserPtr& getUser()
		{
			return replyTo;
		}
	private:
		PrivateFrame(const UserPtr& replyTo_, Client* c) : replyTo(replyTo_),
			created(false), closed(false), isoffline(false), curCommandPosition(0),
			ctrlMessageContainer(WC_EDIT, this, PM_MESSAGE_MAP),
			ctrlClientContainer(WC_EDIT, this, PM_MESSAGE_MAP) // !Decker!
			, m_bUseTempMultiChat(false)
			, m_bProcessNextChar(false)
		{
			ctrlClient.setClient(c);
		}
		
		virtual ~PrivateFrame() { }
		
		bool created;
		typedef unordered_map<UserPtr, PrivateFrame*, User::Hash> FrameMap;
		typedef FrameMap::const_iterator FrameIter;
		static FrameMap frames;
		ChatCtrl ctrlClient;
		CEdit ctrlMessage;
		CStatusBarCtrl ctrlStatus;
		
		bool m_bProcessNextChar; // [+] SSA
		bool m_bUseTempMultiChat; // [+] SSA
		
		OMenu grantMenu; // !SMT!-UI
		OMenu textMenu;
		OMenu tabMenu;
		
		MessagePanel msgPanel;
		
		UserPtr replyTo;
		CContainedWindow ctrlMessageContainer;
		CContainedWindow ctrlClientContainer;
		
		bool closed;
		bool isoffline;
		
		StringMap ucLineParams;
		
		void updateTitle();
		
		TStringList prevCommands;
		tstring currentCommand;
		TStringList::size_type curCommandPosition;
		
		// ClientManagerListener
		virtual void on(ClientManagerListener::UserUpdated, const OnlineUserPtr& aUser) noexcept   // !SMT!-fix
		{
			if (aUser->getUser() == replyTo) // !SMT!-fix
			{
				ctrlClient.setClient(const_cast<Client*>(&aUser->getClient()));
				PostMessage(WM_SPEAKER, USER_UPDATED);
			}
		}
		virtual void on(ClientManagerListener::UserConnected, const UserPtr& aUser) noexcept
		{
			if (aUser == replyTo)
				PostMessage(WM_SPEAKER, USER_UPDATED);
		}
		virtual void on(ClientManagerListener::UserDisconnected, const UserPtr& aUser) noexcept
		{
			if (aUser == replyTo)
			{
				ctrlClient.setClient(NULL);
				PostMessage(WM_SPEAKER, USER_UPDATED);
			}
		}
		virtual void on(SettingsManagerListener::Save, SimpleXML& /*xml*/) noexcept;
		LRESULT OnTextTranscode(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/) // [+] Drakon
		{
			WinUtil::TextTranscode(ctrlMessage);
			return 0;
		}
};

#endif // !defined(PRIVATE_FRAME_H)

/**
 * @file
 * $Id: PrivateFrame.h 568 2011-07-24 18:28:43Z bigmuscle $
 */
